package top.xia17.plugins.fast.common.security.anonymous;

import lombok.RequiredArgsConstructor;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import java.util.*;

/**
 * 匿名注解访问配置类
 * @author xia17
 * @date 2022/2/21
 */
@Configuration
@ConditionalOnClass(WebSecurityConfiguration.class)
@ConditionalOnBean(RequestMappingHandlerMapping.class)
@RequiredArgsConstructor
public class AnonymousReqConfiguration {

    private final RequestMappingHandlerMapping requestMappingHandlerMapping;


    /**
     * 将存储所有可匿名访问的路由
     * @return AnonymousRequestStore
     */
    @Bean
    public AnonymousRequestPathStore anonymousRequestStore(){
        Map<RequestMappingInfo, HandlerMethod> handlerMethodMap = requestMappingHandlerMapping.getHandlerMethods();
        return parseAnonymousUrl(handlerMethodMap);
    }

    /**
     * 解析
     * @param handlerMethodMap /
     * @return /
     */
    private AnonymousRequestPathStore parseAnonymousUrl(Map<RequestMappingInfo, HandlerMethod> handlerMethodMap){
        Set<String> get = new HashSet<>();
        Set<String> post = new HashSet<>();
        Set<String> put = new HashSet<>();
        Set<String> patch = new HashSet<>();
        Set<String> delete = new HashSet<>();
        Set<String> all = new HashSet<>();
        for (Map.Entry<RequestMappingInfo, HandlerMethod> infoEntry : handlerMethodMap.entrySet()) {
            HandlerMethod handlerMethod = infoEntry.getValue();
            AnonymousAccess anonymousAccess = handlerMethod.getMethodAnnotation(AnonymousAccess.class);
            if (anonymousAccess != null) {
                List<RequestMethod> requestMethods = new ArrayList<>(infoEntry.getKey().getMethodsCondition().getMethods());
                RequestMethodEnum request = RequestMethodEnum.find(requestMethods.size() == 0 ? RequestMethodEnum.ALL.getType() : requestMethods.get(0).name());
                switch (Objects.requireNonNull(request)) {
                    case GET -> get.addAll(infoEntry.getKey().getPathPatternsCondition().getPatternValues());
                    case POST -> post.addAll(infoEntry.getKey().getPathPatternsCondition().getPatternValues());
                    case PUT -> put.addAll(infoEntry.getKey().getPathPatternsCondition().getPatternValues());
                    case PATCH -> patch.addAll(infoEntry.getKey().getPathPatternsCondition().getPatternValues());
                    case DELETE -> delete.addAll(infoEntry.getKey().getPathPatternsCondition().getPatternValues());
                    default -> all.addAll(infoEntry.getKey().getPathPatternsCondition().getPatternValues());
                }
            }
        }
        AnonymousRequestPathStore store = new AnonymousRequestPathStore();
        store.setGetPaths(get);
        store.setPostPaths(post);
        store.setPutPaths(put);
        store.setPatchPaths(patch);
        store.setDeletePaths(delete);
        store.setAllPaths(all);
        return store;
    }

}
